/**
 * chenuu.com
 * 
 * @author  zhaoxu.com@gmail.com
 * @created 2012-11-14
 */
package com.chenuu.common.config;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import com.chenuu.common.config.value.IntegerValueFactory;
import com.chenuu.common.config.value.StringValueFactory;
import com.chenuu.common.config.value.ValueFactory;
import com.chenuu.common.exceptions.ChenuuException;

/**
 *
 */
public class PropertiesConfigFactory {

	private static Map<Class<?>, Object> configMap;
	private static Map<Class<?>, ValueFactory> valueFactoryMap;

	static {
		configMap = new HashMap<Class<?>, Object>();
		
		valueFactoryMap = new HashMap<Class<?>, ValueFactory>();
		valueFactoryMap.put(String.class, new StringValueFactory());
		valueFactoryMap.put(Integer.class, new IntegerValueFactory());
	}

	@SuppressWarnings("unchecked")
	public static <T> T getConfig(Class<T> clazz) {

		Object config = configMap.get(clazz);
		if (config == null) {
			T t = loadConfig(clazz);
			configMap.put(clazz, t);
			return t;
		} else {
			return ((T) configMap.get(clazz));
		}

	}
	
	private static <T> T loadConfig(Class<T> clazz) {
		PropertiesResource resource = clazz.getAnnotation(PropertiesResource.class);

		Properties props = new Properties();
		try {
			props.load(Thread.currentThread().getContextClassLoader()
					.getResourceAsStream(resource.value()));
		} catch (IOException e) {
			throw new ChenuuException("加载配置文件失败。", e);
		}

		T t;
		try {
			t = clazz.newInstance();
		} catch (Exception e) {
			throw new ChenuuException("构造配置对象实例失败。", e);
		}

		Field[] fields = clazz.getDeclaredFields();
		for (Field f : fields) {
			PropertiesField propertiesField = f.getAnnotation(PropertiesField.class);
			if (propertiesField != null) {
				String propKey = propertiesField.value();
				String propValue = props.getProperty(propKey).trim();
				
				Class<?> valueType = propertiesField.type();
				ValueFactory vf = valueFactoryMap.get(valueType);
				vf.setValue(t, f.getName() , propValue);
			}
		}

		return t;
	}

}
